package requesthandler

import (
	"encoding/json"
	"fmt"
	"gitee.com/jamon/espoir_go/common"
	"gitee.com/jamon/espoir_go/logger"
	BaseHandler "gitee.com/jamon/espoir_go/service"
	"tankserver/lib"
	"tankserver/requesthandler/room"
)

type RoomPlugin struct {
	BaseHandler.ReqBasePlugin
}

func NewRoomPlugin() *RoomPlugin {
	plugin := &RoomPlugin{
		ReqBasePlugin: BaseHandler.ReqBasePlugin{
			RouteGroupID: lib.RouteGroupID_Room,
			RouteMod:     lib.RouteMod_Room,
			PluginName:   "room",
			MsgBaseID:    lib.MsgID_MODULE_ROOM,
		},
	}

	return plugin
}

func (p *RoomPlugin) Start() (err error) {
	return
}

func (p *RoomPlugin) Stop() error {
	//TODO implement me
	panic("implement me")
}

func (p *RoomPlugin) GetRouteInfo(req *common.MsgRequest) (routeGroupID uint32, subAddress uint32, err error) {
	// create room时根据该方法寻址，其他请求根据roomID寻址
	_, seq, err := common.ParseSessionID(req.SessionID)
	if err != nil {
		return
	}
	subAddress = seq % p.RouteMod
	return p.RouteGroupID, subAddress, nil
}

func (p *RoomPlugin) HandleMsg(req *common.MsgRequest, res *common.MsgResponse) (err error) {
	switch req.MsgId {
	case lib.MsgID_ROOM_CREATE:
		err = p.handleCreate(req, res)
	case lib.MsgID_ROOM_JOIN_MATCH:
		err = p.handleJoin(req, res)
	case lib.MsgID_ROOM_READY:
		err = p.handleReady(req, res)
	case lib.MsgID_ROOM_GAME_OVER:
		err = p.handleGameOver(req, res)
	case lib.MsgID_ROOM_GAME_OP:
		err = p.handleGameOp(req, res)
	default:
		err = fmt.Errorf("unknownMsg|room|id=%v", req.MsgId)
	}
	return
}

func (p *RoomPlugin) handleCreate(req *common.MsgRequest, res *common.MsgResponse) (err error) {
	data := lib.CreateRoomRequest{}
	err = json.Unmarshal(req.Data, &data)
	if err != nil {
		logger.Error("handleCreate: invalid request data: ", logger.Kwargs{"data": string(req.Data)})
		return
	}
	userID, err := p.GetUserID(req.SessionID)
	if err != nil {
		logger.Error("handleCreate: get user id failed: ", logger.Kwargs{"err": err})
		return
	}
	gameID, _ := room.GetRoomManager().CreateRoom(userID, data.GameType, data.RoomType)
	res.Data, err = json.Marshal(p.Response(common.MsgCode_SUCCESS, lib.CreateRoomResponse{RoomID: gameID}))
	return
}

func (p *RoomPlugin) handleJoin(req *common.MsgRequest, res *common.MsgResponse) (err error) {
	defer func() {
		logger.Info("end", logger.Kwargs{"req_Data": string(req.Data), "res_Data": string(res.Data)})
	}()
	data := lib.JoinMatchRoomRequest{}
	err = json.Unmarshal(req.Data, &data)
	if err != nil {
		logger.Error("handleJoin: invalid request data: ", logger.Kwargs{"data": string(req.Data)})
		return
	}
	userID, err := p.GetUserID(req.SessionID)
	if err != nil {
		logger.Error("handleJoin: get user id failed: ", logger.Kwargs{"err": err})
		return
	}
	desc, err := room.GetRoomManager().JoinMatchRoom(userID, data.GameType)
	res.Data, err = json.Marshal(p.Response(common.MsgCode_SUCCESS, lib.JoinMatchRoomResponse{Desc: desc}))
	return
}

func (p *RoomPlugin) handleGameOp(req *common.MsgRequest, res *common.MsgResponse) (err error) {
	data := lib.GameOpRequest{}
	err = json.Unmarshal(req.Data, &data)
	if err != nil {
		logger.Error("handleGameOp: invalid request data: ", logger.Kwargs{"data": string(req.Data)})
		return
	}
	userID, err := p.GetUserID(req.SessionID)
	if err != nil {
		logger.Error("handleGameOp: get user id failed: ", logger.Kwargs{"err": err})
		return
	}
	roomID := room.GetRoomManager().AddOp(userID, data.Op)
	if roomID == "" {
		logger.Error("handleGameOp: add op failed: ", logger.Kwargs{"err": err})
		return
	}
	res.Data, err = json.Marshal(p.Response(common.MsgCode_SUCCESS, lib.GameOpResponse{Desc: "ok"}))
	return
}

func (p *RoomPlugin) handleReady(req *common.MsgRequest, res *common.MsgResponse) (err error) {
	defer func() {
		logger.Info("end", logger.Kwargs{"req_Data": string(req.Data), "res_Data": string(res.Data)})
	}()
	data := lib.SetReadyRequest{}
	err = json.Unmarshal(req.Data, &data)
	if err != nil {
		logger.Error("handleReady: invalid request data: ", logger.Kwargs{"data": string(req.Data)})
		return
	}
	userID, err := p.GetUserID(req.SessionID)
	if err != nil {
		logger.Error("handleReady: get user id failed: ", logger.Kwargs{"err": err})
		return
	}
	roomID := room.GetRoomManager().SetReadyStatus(userID, data.Status)
	if roomID == "" {
		logger.Error("handleReady: set ready status failed: ", logger.Kwargs{"err": err})
		return
	}

	isStart := room.GetRoomManager().CheckStartGame(roomID)
	if isStart {
		logger.Info("handleReady: start game", logger.Kwargs{"room_id": roomID})
		// 通知玩家开始游戏
		go common.SafeRun(func() {
			room.GetRoomManager().StartGame(roomID)
		})
	}

	res.Data, err = json.Marshal(p.Response(common.MsgCode_SUCCESS, lib.SetReadyResponse{Desc: "ok"}))
	return
}

func (p *RoomPlugin) handleGameOver(req *common.MsgRequest, res *common.MsgResponse) (err error) {
	data := lib.GameOverRequest{}
	err = json.Unmarshal(req.Data, &data)
	if err != nil {
		logger.Error("handleGameOver: invalid request data: ", logger.Kwargs{"data": string(req.Data)})
		return
	}
	userID, err := p.GetUserID(req.SessionID)
	if err != nil {
		logger.Error("handleGameOver: get user id failed: ", logger.Kwargs{"err": err})
		return
	}
	mgr := room.GetRoomManager()
	roomID := mgr.SetReadyStatus(userID, room.REadyStatus_GAME_OVER)
	isOver := mgr.CheckGameOver(roomID)
	if isOver {
		mgr.GameOver(roomID, data.IsWin)
	}
	res.Data, err = json.Marshal(p.Response(common.MsgCode_SUCCESS, lib.GameOverResponse{Desc: "ok"}))
	return
}

var roomPlugin BaseHandler.ReqPluginInterface = NewRoomPlugin()

func init() {
	err := BaseHandler.RegisterReqPlugin(lib.MsgID_MODULE_ROOM, &roomPlugin)
	if err != nil {
		panic(err)
	}
}
